﻿/**
 *  以下代码主要来自：
 *  OpenCV3 Computer Vision Application Programming Cookbook
 *  
 *  部分代码有改编。
 */

#if !defined HISTOGRAM
#define HISTOGRAM

#include <opencv2/core.hpp>
#include <opencv2/imgproc.hpp>

// To create histograms of gray-level images
class Histogram1D 
{
public:

	Histogram1D();

	// Sets the channel on which histogram will be calculated.
	// By default it is channel 0.
	void setChannel(int c);

	// Gets the channel used.
	int getChannel();

	// Sets the range for the pixel values.
	// By default it is [0,256[
	void setRange(float minValue, float maxValue);

	// Gets the min pixel value.
	float getMinValue();

	// Gets the max pixel value.
	float getMaxValue();

	// Sets the number of bins in histogram.
	// By default it is 256.
	void setNBins(int nbins);

	// Gets the number of bins in histogram.
	int getNBins();

	// Computes the 1D histogram.
	cv::Mat getHistogram(const cv::Mat &image);

    // Computes the 1D histogram and returns an image of it.
	cv::Mat getHistogramImage(const cv::Mat &image, int zoom = 1);

    // Stretches the source image using min number of count in bins.
    cv::Mat stretch(const cv::Mat &image, int minValue = 0);

    // Stretches the source image using percentile.
    cv::Mat stretch(const cv::Mat &image, double percentile);
    cv::Mat stretch(const cv::Mat &image, double percentile1, double percentile2);
    
    cv::Mat normalize(const cv::Mat &image);
    // static methods

    // Create an image representing a histogram
    static cv::Mat getImageOfHistogram(const cv::Mat &hist, int zoom);

    // Equalizes the source image.
    static cv::Mat equalize(const cv::Mat &image);
    
	// Applies a lookup table transforming an input image into a 1-channel image
    static cv::Mat applyLookUp(const cv::Mat& image, const cv::Mat& lookup);

	// Applies a lookup table transforming an input image into a 1-channel image
	// this is a test version with iterator; always use function cv::LUT
    static cv::Mat applyLookUpWithIterator(const cv::Mat& image, const cv::Mat& lookup);

private:

    int histSize[1];         // number of bins in histogram
	float hranges[2];        // range of values
    const float * ranges[1];  // pointer to the different value ranges
    int channels[1];         // channel number to be examined
};

class ColorHistogram 
{
  public:

	ColorHistogram();

	// set histogram size for each dimension
	void setSize(int size);

	// Computes the histogram.
	cv::Mat getHistogram(const cv::Mat &image);

	// Computes the histogram.
	cv::SparseMat getSparseHistogram(const cv::Mat &image);
    
	// Computes the 1D Hue histogram.
	// BGR source image is converted to HSV
	// Pixels with low saturation are ignored
	cv::Mat getHueHistogram(const cv::Mat &image, int minSaturation = 0);

	// Computes the 2D ab histogram.
	// BGR source image is converted to Lab
	cv::Mat getabHistogram(const cv::Mat &image);
    
private:
    int histSize[3];        // size of each dimension
	float hranges[2];       // range of values (same for the 3 dimensions)
    const float* ranges[3]; // array of ranges for each dimension
    int channels[3];        // channel to be considered
};

class ContentFinder
{
  public:
    ContentFinder();

    // Sets the threshold on histogram values [0,1]
    void setThreshold(float t);

    // Gets the threshold
    float getThreshold();

    // Sets the reference histogram
    void setHistogram(const cv::Mat& h);

    // Sets the reference histogram
    void setHistogram(const cv::SparseMat& h);

    // Simplified version in which
    // all channels used, with range [0,256[
    cv::Mat find(const cv::Mat& image);

    // Finds the pixels belonging to the histogram
    cv::Mat find(const cv::Mat& image, float minValue, float maxValue, int *channels);
private:

  // histogram parameters
  float hranges[2];
  const float * ranges[3];
  int channels[3];

  float threshold;           // decision threshold
  cv::Mat histogram;         // histogram can be sparse
  cv::SparseMat shistogram;  // or not
  bool isSparse;
};

class ImageComparator
{
public:
    ImageComparator();

    // Set number of bins used when comparing the histograms
    void setNumberOfBins( int bins);
    int getNumberOfBins();

    // set and compute histogram of reference image
    void setReferenceImage(const cv::Mat& image);
    // compare the image using their BGR histograms
    double compare(const cv::Mat& image);
private:

  cv::Mat refH;       // reference histogram
  cv::Mat inputH;     // histogram of input image
  ColorHistogram hist;
  int nBins; // number of bins used in each color channel
};

#endif
